package com.powernode.filter;

/**
 * @Author LF
 * projectName:today-shop
 * description:
 * time:2022-09-18 21:20
 */

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.powernode.constant.AuthConstant;
import com.powernode.constant.ResourceConstant;
import com.powernode.domain.LoginSysUser;
import com.powernode.model.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.time.Duration;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 解析就是拿到token,去查redis,转换成认证对象,放入security上下文中
 */
public class TokenTranslateFilter extends OncePerRequestFilter {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding("UTF-8");

        String authorization = request.getHeader(AuthConstant.AUTHORIZATION);
        if(StringUtils.hasText(authorization)){
            String token = authorization.replaceFirst(AuthConstant.BEARER, "");
            String authenticationStr = redisTemplate.opsForValue().get(AuthConstant.LOGIN_TOKEN_PREFIX + token);
            UsernamePasswordAuthenticationToken authenticationToken = JSON.parseObject(authenticationStr, UsernamePasswordAuthenticationToken.class);
            LoginSysUser loginSysUser = JSON.parseObject(authenticationToken.getPrincipal().toString(), LoginSysUser.class);

            String requestIp = request.getRemoteAddr();
            if (!requestIp.equals(loginSysUser.getIp())) {
                handlerFailResp(response);
                return;
            }

            Long  expireTime = redisTemplate.getExpire(AuthConstant.LOGIN_TOKEN_PREFIX + token,TimeUnit.SECONDS);
           if(expireTime< AuthConstant.TOKEN_EXPIRE_THRESHOLD){
               redisTemplate.expire(AuthConstant.LOGIN_TOKEN_PREFIX+token, Duration.ofSeconds(AuthConstant.TOKEN_EXPIRE_TIME));
           }
            //String authenticationStr = redisTemplate.opsForValue().get(AuthConstant.LOGIN_TOKEN_PREFIX + token);
            //UsernamePasswordAuthenticationToken authenticationToken = JSON.parseObject(authenticationStr, UsernamePasswordAuthenticationToken.class);
            //LoginSysUser loginSysUser = JSON.parseObject(authenticationToken.getPrincipal().toString(), LoginSysUser.class);

            Set<String> auths = loginSysUser.getAuths();
            List<SimpleGrantedAuthority> authorityList = auths.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
            UsernamePasswordAuthenticationToken realAuthenticationToken = new UsernamePasswordAuthenticationToken(loginSysUser, null, authorityList);
            SecurityContextHolder.getContext().setAuthentication(realAuthenticationToken);
        }
        // 拿请求路径
        String path = request.getRequestURI();
        if (ResourceConstant.MY_RPC_URLS.contains(path)) {
            // 判断有没有带我们的rpcToken
            String myRpcToken = request.getHeader(AuthConstant.MY_RPC_TOKEN_PREFIX);
            // 查询redis有没有
            if (StringUtils.hasText(myRpcToken) && redisTemplate.hasKey(AuthConstant.MY_RPC_TOKEN_PREFIX + ":" + myRpcToken)) {
                // 删掉
                redisTemplate.delete(AuthConstant.MY_RPC_TOKEN_PREFIX + ":" + myRpcToken);
            } else {
                handlerFailResp(response);
                return;
            }
        }
        filterChain.doFilter(request,response);
    }

    private void handlerFailResp(HttpServletResponse response) {
        Result<Object> result = Result.fail(HttpStatus.UNAUTHORIZED.value(), "非法访问");
        ObjectMapper objectMapper = new ObjectMapper();
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        String s = null;
        try {
            s = objectMapper.writeValueAsString(result);
            PrintWriter writer = response.getWriter();
            writer.write(s);
            writer.flush();
            writer.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
